
package com.dyzx.hbb.common.utils;

import com.dyzx.hbb.security.service.AuthService;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.crypto.SecretKey;
import java.security.SecureRandom;
import java.util.Base64;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * JWT工具类
 */
@Component
public class JwtUtils {

    /**
     * token请求头名称
     */
    private static final String TOKEN_HEADER = "Authorization";

    /**
     * token前缀
     */
    private static final String TOKEN_PREFIX = "Bearer ";

    /**
     * JWT密钥 (Base64编码)
     */
    @Value("${jwt.secret:}")
    private String secret;

    /**
     * token有效期（默认2小时）
     */
    @Value("${jwt.expiration:7200000}")
    private long expiration;

  //  @Autowired
  //  private AuthService authService;
    /**
     * 在构造函数中检查密钥，如果不存在或不安全，则生成新的安全密钥
     */
    public JwtUtils() {
        try {
            if (secret == null || secret.isEmpty() || secret.equals("your-secret-key")) {
                byte[] key = new byte[32];  // 256 bits
                new SecureRandom().nextBytes(key);
                String newSecret = Base64.getEncoder().encodeToString(key);
                System.out.println("\n警告: 未找到有效的JWT密钥或密钥不安全。");
                System.out.println("已生成新的安全密钥 (Base64编码):");
                System.out.println(newSecret);
                System.out.println("\n请将此密钥添加到application.yml:");
                System.out.println("jwt:");
                System.out.println("  secret: " + newSecret);
                System.out.println("\n或添加到application.properties:");
                System.out.println("jwt.secret=" + newSecret);
                System.out.println("\n添加密钥后重启应用。\n");
            }
        } catch (Exception e) {
            // 忽略异常，让应用继续启动
        }
    }

    /**
     * 生成安全的JWT密钥
     * 此方法用于生成一个新的安全密钥，并将其转换为Base64编码的字符串
     * 生成的密钥满足JWT HMAC-SHA256算法的安全要求（密钥长度 >= 256位）
     *
     * @return Base64编码的密钥字符串
     */
    public static String generateSecureSecret() {
        SecretKey key = Keys.secretKeyFor(SignatureAlgorithm.HS256);
        return Base64.getEncoder().encodeToString(key.getEncoded());
    }

    /**
     * 从Base64编码的字符串中获取SecretKey
     *
     * @param base64Secret Base64编码的密钥字符串
     * @return SecretKey对象
     */
    private SecretKey getSecretKey(String base64Secret) {
        byte[] decodedKey = Base64.getDecoder().decode(base64Secret);
        return Keys.hmacShaKeyFor(decodedKey);
    }

    /**
     * 从请求中获取token
     *
     * @param request HTTP请求
     * @return token字符串，如果没有找到则返回null
     */
    public static String getToken(HttpServletRequest request) {
        String header = request.getHeader(TOKEN_HEADER);
        System.out.println("Authorization header: " + header);
        if (StringUtils.hasText(header) && header.startsWith(TOKEN_PREFIX)) {
            return header.substring(TOKEN_PREFIX.length());
        }
        return null;
    }

    /**
     * 从Authorization header中获取token
     *
     * @param header Authorization header值
     * @return token字符串，如果没有找到则返回null
     */
    public String getToken(String header) {
        if (StringUtils.hasText(header) && header.startsWith(TOKEN_PREFIX)) {
            return header.substring(TOKEN_PREFIX.length());
        }
        return null;
    }

    /**
     * 生成JWT token
     *
     * @param userId 用户ID
     * @param username 用户名
     * @return JWT token
     */
    public String generateToken(Long userId, String username) {
        Map<String, Object> claims = new HashMap<>();
        claims.put("userId", userId);
        claims.put("username", username);
        return generateToken(claims);
    }

    /**
     * 从token中获取用户ID
     *
     * @param token JWT token
     * @return 用户ID
     */
    public Long getUserId(String token) {
        Claims claims = getClaimsFromToken(token);
        return claims != null ? claims.get("userId", Long.class) : null;
    }

    /**
     * 从token中获取用户名
     *
     * @param token JWT token
     * @return 用户名
     */
    public String getUsernameFromToken(String token) {
        Claims claims = getClaimsFromToken(token);
        return claims != null ? claims.get("username", String.class) : null;
    }
    public Long getExpiration(String token) {
        Claims claims = getClaimsFromToken(token);
        return claims != null ? claims.getExpiration().getTime(): null;
    }

    /**
     * 验证token是否有效
     *
     * @param token JWT token
     * @return 如果有效返回true，否则返回false
     */
    public boolean validateToken(String token) {
        if (token == null) {
            System.out.println("Token validation failed: token is null");
            return false;
        }
      //  boolean valid = authService.validateToken(token);

        try {
            SecretKey key = getSecretKey(secret);
            Claims claims = Jwts.parserBuilder()
                    .setSigningKey(key)
                    .build()
                    .parseClaimsJws(token)
                    .getBody();

            if (claims == null) {
                System.out.println("Token validation failed: claims is null");
                return false;
            }

            if (isTokenExpired(claims)) {
                System.out.println("Token validation failed: token is expired");
                System.out.println("Expiration: " + claims.getExpiration());
                System.out.println("Current time: " + new Date());
              //  return false;
                throw  new ExpiredJwtException(null, null, "Token expired");
            }

            // 打印token信息用于调试
            System.out.println("Token validation successful");
            System.out.println("Token claims: " + claims);
            System.out.println("User ID: " + claims.get("userId"));
            System.out.println("Username: " + claims.get("username"));
            System.out.println("Issued at: " + claims.getIssuedAt());
            System.out.println("Expiration: " + claims.getExpiration());

            return true;
        } catch (Exception e) {
            System.out.println("Token validation failed with exception: " + e.getClass().getName());
            System.out.println("Error message: " + e.getMessage());
     throw  new ExpiredJwtException(null, null, "Token expired");// 重新抛出异常，以便调用者可以处理 ExpiredJwtException( null, null, "Token expired");// 重新抛出异常，以便调用者可以处理
        }
    }

    /**
     * 验证token是否有效
     *
     * @param token    JWT token
     * @param username 用户名
     * @return 如果有效返回true，否则返回false
     */
    public boolean validateToken(String token, String username) {
        String tokenUsername = getUsernameFromToken(token);
        return (tokenUsername.equals(username)) && validateToken(token);
    }

    /**
     * 判断token是否可以被刷新
     *
     * @param token JWT token
     * @return 如果可以刷新返回true，否则返回false
     */
    public boolean canTokenBeRefreshed(String token) {
        return validateToken(token);
    }

    /**
     * 刷新token
     *
     * @param token JWT token
     * @return 新的JWT token
     */
    public String refreshToken(String token) {
        Claims claims = getClaimsFromToken(token);
        claims.setIssuedAt(new Date());
        return generateToken(claims);
    }

    /**
     * 生成JWT token
     *
     * @param claims token中要包含的数据
     * @return JWT token
     */
    private String generateToken(Map<String, Object> claims) {
        try {
            SecretKey key = getSecretKey(secret);
            return Jwts.builder()
                    .setClaims(claims)
                    .setIssuedAt(new Date())
                    .setExpiration(new Date(System.currentTimeMillis() + expiration))
                    .signWith(key, SignatureAlgorithm.HS256)
                    .compact();
        } catch (Exception e) {
            System.out.println("Error generating token: " + e.getMessage());
            e.printStackTrace();
            throw new IllegalStateException("Failed to generate JWT token", e);
        }
    }

    /**
     * 从token中获取JWT中的负载
     *
     * @param token JWT token
     * @return Claims对象
     */
    private Claims getClaimsFromToken(String token) {
        try {
            SecretKey key = getSecretKey(secret);
            return Jwts.parserBuilder()
                    .setSigningKey(key)
                    .build()
                    .parseClaimsJws(token)
                    .getBody();
        } catch (Exception e) {
            System.out.println("Error parsing token claims: " + e.getMessage());
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 判断token是否过期
     *
     * @param claims Claims对象
     * @return 如果过期返回true，否则返回false
     */
    private boolean isTokenExpired(Claims claims) {
        return claims.getExpiration().before(new Date());
    }

    /**
     * 用于生成安全的JWT密钥
     */
    public static void main(String[] args) {
        String secureSecret = generateSecureSecret();
        System.out.println("Generated JWT secret key (Base64 encoded):");
        System.out.println(secureSecret);
        System.out.println("\nAdd this to your application.yml or application.properties as:");
        System.out.println("jwt.secret=" + secureSecret);
    }
}